import { Vector3 } from "@babylonjs/core/Maths/math";
import { ARROW_MODE, HardLineGeometry, IHardLineGeometryOptions } from "./hard-line-geometry";
import { Scene } from "@babylonjs/core/scene";
import { Mesh } from "@babylonjs/core/Meshes/mesh";
import { Buffer } from "@babylonjs/core/Buffers/buffer";

/**
 * 软角线几何体参数对象
 * @param dashSize 虚线段长
 * @param gapSize 虚线空白长
 */
interface ISoftLineGeometryOptions {
    dashSize?: number,
    gapSize?: number
}


/**
 * 软角线几何体（显示有缺陷，不支持箭头，但拐角uv连续，半透明无重叠）
 * @param name 几何体id
 * @param vertices 顶点集
 * @param options 参数对象
 * @param scene 所在场景
 * @param mesh 应用到的网格
 */
class SoftLineGeometry extends HardLineGeometry {

    private _prePositions!: Float32Array;
    private _dirPositions!: Float32Array;

    constructor(name: string, vertices: Vector3[], options?: ISoftLineGeometryOptions, scene?: Scene, mesh?: Mesh) {
        super(name, vertices, options, scene, mesh);
    }

    public update(): void {
        super.update();
        this.getVertexBuffer('prePosition')?.update(this._prePositions);
        this.getVertexBuffer('dirPosition')?.update(this._dirPositions);
    }

    protected initializeVariable(vertices: Vector3[], options?: IHardLineGeometryOptions): void {
        super.initializeVariable(vertices, options);
        const s3 = (this._maxSegments * 2 - 3) * 6 * 3;
        this._prePositions = new Float32Array(s3);
        this._dirPositions = new Float32Array(s3);
    }
    protected resizeDataArray(length1: number, length3: number): void {
        super.resizeDataArray(length1, length3);
        this._prePositions = new Float32Array(length3);
        this._dirPositions = new Float32Array(length3);
    }
    protected setAttribute(): void {
        super.setAttribute();
        const engine = this.getEngine();

        let bfr = this.getVertexBuffer('prePosition');
        if (bfr) bfr.dispose();
        const prePositionRefBuffer = new Buffer(engine, this._prePositions, true, 3);
        this.setVerticesBuffer(prePositionRefBuffer.createVertexBuffer('prePosition', 0, 3));

        bfr = this.getVertexBuffer('dirPosition');
        if (bfr) bfr.dispose();
        const dirPositionRefBuffer = new Buffer(engine, this._dirPositions, true, 3);
        this.setVerticesBuffer(dirPositionRefBuffer.createVertexBuffer('dirPosition', 0, 3));
    }
    protected rectifyPoints(ps: Vector3[]): Vector3[] {
        return ps;
    }
    protected pushData(...datas: Array<number | Vector3>): void {
        super.pushData(...datas);
        const i3 = datas[0] as number;
        const pp = datas[6] as Vector3;
        const dp = datas[7] as Vector3;

        this._prePositions[i3] = pp!.x;
        this._prePositions[i3 + 1] = pp!.y;
        this._prePositions[i3 + 2] = pp!.z;
        this._dirPositions[i3] = dp!.x;
        this._dirPositions[i3 + 1] = dp!.y;
        this._dirPositions[i3 + 2] = dp!.z;
    }
    protected pushSolidData(vs: Vector3[]): void {
        const n0 = this._tV0;
        const n1 = this._tV1;
        const pp0 = this._tV2;
        const pp1 = this._tV3;
        const dp0 = this._tV4;
        const dp1 = this._tV5;
        const nnp = this._tV6;
        for (let i = 0; i < vs.length - 1; i++) {
            const cp = vs[i];
            const np = vs[i + 1];
            if (i === 0) {
                n0.copyFrom(np);
                n1.copyFrom(np).subtractInPlace(cp).normalize().addInPlace(np);

                pp1.copyFrom(cp);
                pp0.copyFrom(cp).subtractInPlace(np).addInPlace(cp);
                if (vs[i + 2]) {
                    nnp.copyFrom(vs[i + 2]);
                } else {
                    nnp.copyFrom(n1);
                }
                dp0.copyFrom(np);
                dp1.copyFrom(nnp);

                this.pushData(0, 0, cp, n0, 1, 1, pp0, dp0);
                this.pushData(3, 1, cp, n0, -1, 1, pp0, dp0);
                this.pushData(6, 2, np, n1, 1, 1, pp1, dp1);
                this.pushData(9, 3, cp, n0, -1, 1, pp0, dp0);
                this.pushData(12, 4, np, n1, -1, 1, pp1, dp1);
                this.pushData(15, 5, np, n1, 1, 1, pp1, dp1);
            } else {
                const i3 = 18 + (i - 1) * 36;
                const i1 = 6 + (i - 1) * 12;
                n0.copyFrom(cp).subtractInPlace(vs[i - 1]).normalize().addInPlace(cp);
                n1.copyFrom(np);

                pp0.copyFrom(vs[i - 1]);
                pp1.copyFrom(vs[i - 1]);
                dp0.copyFrom(np);
                dp1.copyFrom(np);

                this.pushData(i3, i1, cp, n0, 1, 1, pp0, dp0);
                this.pushData(i3 + 3, i1 + 1, cp, n0, -1, 1, pp0, dp0);
                this.pushData(i3 + 6, i1 + 2, cp, n1, 1, 1, pp1, dp1);
                this.pushData(i3 + 9, i1 + 3, cp, n0, -1, 1, pp0, dp0);
                this.pushData(i3 + 12, i1 + 4, cp, n1, -1, 1, pp1, dp1);
                this.pushData(i3 + 15, i1 + 5, cp, n1, 1, 1, pp1, dp1);

                n0.copyFrom(np);
                n1.copyFrom(np).subtractInPlace(cp).normalize().addInPlace(np);

                if (vs[i + 2]) {
                    nnp.copyFrom(vs[i + 2]);
                } else {
                    nnp.copyFrom(n1);
                }
                pp0.copyFrom(vs[i - 1]);
                pp1.copyFrom(cp);
                dp0.copyFrom(np);
                dp1.copyFrom(nnp);

                this.pushData(i3 + 18, i1 + 6, cp, n0, 1, 1, pp0, dp0);
                this.pushData(i3 + 21, i1 + 7, cp, n0, -1, 1, pp0, dp0);
                this.pushData(i3 + 24, i1 + 8, np, n1, 1, 1, pp1, dp1);
                this.pushData(i3 + 27, i1 + 9, cp, n0, -1, 1, pp0, dp0);
                this.pushData(i3 + 30, i1 + 10, np, n1, -1, 1, pp1, dp1);
                this.pushData(i3 + 33, i1 + 11, np, n1, 1, 1, pp1, dp1);
            }
        }
    }

    public get arrowMode() {
        return ARROW_MODE.NONE;
    }
    public set arrowMode(mode: ARROW_MODE) {
    }
    public get arrowLengthRatio() {
        return 0;
    }
    public set arrowLengthRatio(ratio: number) {
    }
    public get arrowWidthRatio() {
        return 0;
    }
    public set arrowWidthRatio(ratio: number) {
    }
}


export { SoftLineGeometry };
export type { ISoftLineGeometryOptions };